package org.muyu;

import org.muyu.component.Component;
import org.muyu.component.ConcreteComponent;
import org.muyu.component.Decorator;
import org.muyu.component.GroupPrizeDecorator;
import org.muyu.component.MonthPrizeDecorator;
import org.muyu.component.SumPrizeDecorator;

/**
 * 结构型模式 => 装饰者模式
 *
 * 组成部件
 * 1. 组件对象的接口【Component】 => Component
 * 2. 具体的组件对象【ConcreteComponent】 => ConcreteComponent
 * 3. 所有装饰器的抽象父类【Decorator】 => Decorator
 * 4. 实际的装饰器对象【ConcreteDecorator】 => GroupPrizeDecorator、MonthPrizeDecorator、SumPrizeDecorator
 *
 * 动态地给一个对象添加一些额外地职责。就增加功能来说，装饰者模式比生成子类更加灵活
 *
 * 案例理解
 * 1. 业务场景为计算每个人地奖金金额，因为人员不同，奖金计算的规则也不同，采用装饰者模式可以动态地给对象添加额外的职责
 * 2. 首先定义一个装饰器的抽象父类，需要和被装饰对象继承一样的父类
 * 3. 然后这个抽象父类去持有被装饰对象的父类引用
 * 4. 然后分别实现不同的装饰者，实现不同的业务规则
 * 5. 最后使用时候，只需先将装饰着组合好，调用即可
 */
public class Client {
    public static void main(String[] args) {
        // 先创建计算基本奖金的类，这也是被装饰的对象
        Component c1 = new ConcreteComponent();

        // 然后对计算的基本奖金进行装饰，这里要组合各个装饰
        // 说明，各个装饰者之间最好是不要有先后顺序的限制，
        // 也就是先装饰谁和后装饰谁都应该是一样的

        // 先组合普通业务人员的奖金计算
        Decorator d1 = new MonthPrizeDecorator(c1);
        Decorator d2 = new SumPrizeDecorator(d1);

        // 注意：这里只需使用最后组合好的对象调用业务方法即可，会依次调用回去
        // 日期对象都没有用上，所以传null就可以了
        double zs = d2.calcPrize("张三",null,null);
        System.out.println("==========张三应得奖金："+zs);
        double ls = d2.calcPrize("李四",null,null);
        System.out.println("==========李四应得奖金："+ls);

        // 如果是业务经理，还需要一个计算团队的奖金计算
        Decorator d3 = new GroupPrizeDecorator(d2);
        double ww = d3.calcPrize("王五",null,null);
        System.out.println("==========王经理应得奖金："+ww);
    }
}
